import time
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix

# 加载数据
data = pd.read_csv('StudentPerformanceFactors.csv')
print(f"原始数据量: {len(data)} 条")

# 删除空值
data = data.dropna()
print(f"去除空值后的数据量: {len(data)} 条")

# 二值编码
binary_cols = {
    'Extracurricular_Activities': {'No': 0, 'Yes': 1},
    'Internet_Access': {'No': 0, 'Yes': 1},
    'Learning_Disabilities': {'No': 0, 'Yes': 1}
}
for col, mapping in binary_cols.items():
    data[col] = data[col].map(mapping)

# 多类别编码
multi_cols = {
    'Parental_Involvement': {'Low': 0, 'Medium': 1, 'High': 2},
    'Access_to_Resources': {'Low': 0, 'Medium': 1, 'High': 2},
    'Motivation_Level': {'Low': 0, 'Medium': 1, 'High': 2},
    'Family_Income': {'Low': 0, 'Medium': 1, 'High': 2},
    'Teacher_Quality': {'Low': 0, 'Medium': 1, 'High': 2},
    'School_Type': {'Public': 0, 'Private': 1},
    'Peer_Influence': {'Negative': 0, 'Neutral': 1, 'Positive': 2},
    'Parental_Education_Level': {'High School': 0, 'College': 1, 'Postgraduate': 2},
    'Distance_from_Home': {'Near': 0, 'Moderate': 1, 'Far': 2},
    'Gender': {'Male': 0, 'Female': 1}
}
for col, mapping in multi_cols.items():
    data[col] = data[col].map(mapping)

# 标签（保持不变）
y = data['Exam_Score']
# 将考试成绩转换为分类标签（示例：根据分数段分类）
# 这里假设60分以下为不及格(0)，60-80为中等(1)，80-90为良好(2)，90-100为优秀(3)
y = pd.cut(y, bins=[0, 60, 80, 90, 100], labels=[0, 1, 2, 3], include_lowest=True)
data = data[~y.isna()]  # 删除转换后产生的空值
y = y.dropna()  # 确保y中没有NaN

# 特征数据划分
X = data.drop(columns=['Exam_Score'])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 特征标准化（用于SVM）
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 分类模型列表
models = {
    "Decision Tree": DecisionTreeClassifier(random_state=42),
    "Random Forest": RandomForestClassifier(n_estimators=100, random_state=42),
    "SVM": SVC(kernel='rbf', C=1.0, random_state=42)
}

# 存储结果
results = []

# 遍历模型并评估
for name, model in models.items():
    start_time = time.time()
    
    # 区分是否需标准化数据
    if name == "SVM":
        model.fit(X_train_scaled, y_train)
        y_pred = model.predict(X_test_scaled)
    else:
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
    
    # 计算分类指标
    accuracy = accuracy_score(y_test, y_pred)
    precision = precision_score(y_test, y_pred, average='weighted')
    recall = recall_score(y_test, y_pred, average='weighted')
    f1 = f1_score(y_test, y_pred, average='weighted')
    elapsed_time = time.time() - start_time

    results.append({
        'Model': name,
        'Accuracy': accuracy,
        'Precision': precision,
        'Recall': recall,
        'F1 Score': f1,
        'Time (s)': round(elapsed_time, 3)
    })

    # 可视化混淆矩阵
    cm = confusion_matrix(y_test, y_pred)
    plt.figure(figsize=(6, 5))
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
                xticklabels=['Fail', 'Pass', 'Good', 'Excellent'],
                yticklabels=['Fail', 'Pass', 'Good', 'Excellent'])
    plt.title(f'{name} - Confusion Matrix')
    plt.xlabel('Predicted')
    plt.ylabel('Actual')
    plt.tight_layout()
    plt.show()

# 转为DataFrame并展示对比
results_df = pd.DataFrame(results)
print("\n分类模型性能比较：")
print(results_df.to_markdown(index=False))